﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;

namespace DotNetCommon.Accessors;
/// <summary>
/// 快速访问给定类型的对象的属性值, 参照: <seealso cref="Accessor"/>
/// </summary>
public class ObjectAccessor : Accessor
{
    private readonly Hashtable _objectGettersCache, _objectSettersCache;
    private readonly Hashtable _objectFieldGettersCache, _objectFieldSettersCache;

    [DebuggerStepThrough]
    internal ObjectAccessor(IReflect type, bool ignoreCase, bool includeNonPublic)
        : base(type, ignoreCase, includeNonPublic)
    {
        _objectGettersCache = new Hashtable(Properties.Count, Comparer);
        _objectSettersCache = new Hashtable(Properties.Count, Comparer);
        _objectFieldGettersCache = new Hashtable(Fields.Count, Comparer);
        _objectFieldSettersCache = new Hashtable(Fields.Count, Comparer);

        //属性
        foreach (var pair in Properties)
        {
            var propName = pair.Key;
            var prop = pair.Value;

            if (prop.CanRead)
            {
                _objectGettersCache[propName] = AccessorBuilder.BuildGetter(prop, IncludesNonPublic);
            }

            if (prop.CanWrite)
            {
                _objectSettersCache[propName] = AccessorBuilder.BuildSetter(prop, IncludesNonPublic);
            }
        }
        //字段
        foreach (var pair in Fields)
        {
            var propName = pair.Key;
            var field = pair.Value;

            _objectFieldGettersCache[propName] = AccessorBuilder.BuildGetter(field);
            if (!field.IsInitOnly)
            {
                _objectFieldSettersCache[propName] = AccessorBuilder.BuildSetter(field);
            }
        }
    }

    /// <summary>
    /// 根据给定的对象和属性[字段]名称对属性[字段]进行读写操作
    /// </summary>
    public object this[object instance, string propertyOrFieldName]
    {
        get
        {
            if (_objectGettersCache[propertyOrFieldName] is Func<object, object> getter)
            {
                return getter(instance);
            }
            else if (_objectFieldGettersCache[propertyOrFieldName] is Func<object, object> getter2)
            {
                return getter2(instance);
            }
            throw new ArgumentException($"Type: \"{instance.GetType().FullName}\" does not have a property or field named: \"{propertyOrFieldName}\" that supports reading.");
        }

        set
        {
            if (_objectSettersCache[propertyOrFieldName] is Action<object, object> setter)
            {
                setter(instance, value);
            }
            else if (_objectFieldSettersCache[propertyOrFieldName] is Action<object, object> setter2)
            {
                setter2(instance, value);
            }
            else
            {
                throw new ArgumentException($"Type: \"{instance.GetType().FullName}\" does not have a property or field named: \"{propertyOrFieldName}\" that supports writing.");
            }
        }
    }
}